package com.dddframework.security.domain.auth.component;

import com.dddframework.core.context.SpringContext;
import com.dddframework.kit.lang.CollKit;
import com.dddframework.security.domain.auth.model.AuthUser;
import com.dddframework.security.domain.contract.event.UserCloseEvent;
import com.dddframework.security.domain.contract.event.UserLoginFailedEvent;
import com.dddframework.security.domain.contract.event.UserLoginSuccessEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * 用户认证监听接口
 * 实现此接口处理其他业务逻辑
 */
public interface UserAuthListenable {
    Logger log = LoggerFactory.getLogger(UserAuthListenable.class);

    /**
     * 处理登录成功
     */
    @EventListener
    default void authSuccess(AuthenticationSuccessEvent event) {
        Authentication authentication = (Authentication) event.getSource();
        if (CollKit.isNotEmpty(authentication.getAuthorities())) {
            AuthUser authUser = AuthUser.of(authentication);
            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
            SpringContext.getApplicationContext().publishEvent(new UserLoginSuccessEvent(request, authUser));
        }
    }

    /**
     * 处理登录失败
     */
    @EventListener
    default void authFailure(AbstractAuthenticationFailureEvent event) {
        AuthenticationException authenticationException = event.getException();
        Authentication authentication = (Authentication) event.getSource();
        log.warn("用户：{} 登录失败，异常：{}", authentication.getPrincipal(), authenticationException.getLocalizedMessage());
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        SpringContext.getApplicationContext().publishEvent(new UserLoginFailedEvent(request));
    }

    /**
     * 登录成功
     * <p>
     * HttpServletRequest request = event.get();
     * BaseUser baseUser = event.getBaseUser();
     * String remoteAddr = ServletUtil.getClientIP(request);
     * String address = IpKit.getAddresses(remoteAddr);
     * String requestUri = URLUtil.getPath(request.getRequestURI());
     * String userAgent = request.getHeader("auth-agent");
     * // 处理登录日志
     * // 更新用户登陆次数
     */
    @Async
    @EventListener
    void loginSuccess(UserLoginSuccessEvent event);

    /**
     * 登录失败
     * HttpServletRequest request = event.get();
     * // 记录登录失败日志
     */
    @Async
    @EventListener
    void loginFailed(UserLoginFailedEvent event);

    /**
     * 用户关闭
     * BaseUser baseUser = event.get();
     */
    @EventListener
    void userClose(UserCloseEvent event);

}